#Copyright (C) Nial Peters 2013
#
#This file is part of AvoPlot.
#
#AvoPlot is free software: you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation, either version 3 of the License, or
#(at your option) any later version.
#
#AvoPlot is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with AvoPlot.  If not, see <http://www.gnu.org/licenses/>.

import wx
import os.path

from avoplot.persist import PersistentStorage
from avoplot.plugins import AvoPlotPluginSimple
from avoplot.subplots import AvoPlotXYSubplot
from avoplot.series import XYDataSeries
from avoplot import controls

from doas.io import SpectrumIO, UnableToLoad
from std_ops.os_ import find_files

plugin_is_GPL_compatible = True


class DOASSpectrumControlPanel(controls.AvoPlotControlPanelBase):
    def __init__(self, series):
        
        self.series = series
        super(DOASSpectrumControlPanel, self).__init__('DOAS')
    
    
    def setup(self, parent):
        
        super(DOASSpectrumControlPanel, self).setup(parent)
        
        normalise_button = wx.Button(self, wx.ID_ANY,"Normalise")
        
        wx.EVT_BUTTON(self, normalise_button.GetId(), self.on_normalise)
        
        self.Add(normalise_button,0,wx.ALIGN_CENTER)
        
        file_list = FileListPanel(self,os.path.dirname(self.series.filename) ,self.series)
        self.Add(file_list, 1, wx.EXPAND)
    
    
    def on_normalise(self, evnt):
        self.series.normalise_intensities()
        self.series.update()


class DOASSpectrumSubplot(AvoPlotXYSubplot):
    def my_init(self):
        ax = self.get_mpl_axes()
        ax.set_xlabel('Wavelength (nm)')
        ax.set_ylabel('Counts')
    

#define new data series type for DOAS data
class DOASSpectrumData(XYDataSeries):
    def __init__(self, filename,*args, **kwargs):
        super(DOASSpectrumData, self).__init__(*args, **kwargs)
        self.filename = filename
        self.add_control_panel(DOASSpectrumControlPanel(self))
        
    @staticmethod
    def get_supported_subplot_type():
        return DOASSpectrumSubplot
    
    def normalise_intensities(self):
        """
        Rescales all the intensities such that the maximum is at 65535 and the 
        minimum is at 0. This overwrites the original y-data of the series and 
        is therefore NOT a reversible operation.
        """
        x,y = self.get_raw_data()
        y = y - y.min()
        y = (y / y.max()) * 65535
        self.set_xy_data(x, y)


class DOASSpectrumPlugin(AvoPlotPluginSimple):
    def __init__(self):
        AvoPlotPluginSimple.__init__(self,"DOAS Spectrum Plugin", DOASSpectrumData)
        
        self.set_menu_entry(['DOAS','DOAS Spectrum'], "Plot a DOAS Spectrum file")
    
    
    def plot_into_subplot(self, subplot):
        loaded_spectra = self.load_spectrum_files()
        
        if not loaded_spectra:
            return False
        
        for spec in loaded_spectra:
            data_series = DOASSpectrumData(spec.filename,
                                           os.path.basename(spec.filename),
                                           xdata=spec.wavelengths, 
                                           ydata=spec.counts)
            
            subplot.add_data_series(data_series)
        
        return True
    
    
    def load_spectrum_files(self):
        persist = PersistentStorage()
        
        try:
            last_path_used = persist.get_value("doas_spectra_dir")
        except KeyError:
            last_path_used = ""
        
        #get filename to open
        fd = wx.FileDialog(self.get_parent(), "Choose spectrum file(s) to open", 
                           defaultDir=last_path_used, style=wx.FD_MULTIPLE | wx.FD_OPEN)
        
        if fd.ShowModal() != wx.ID_OK:
            return []
        
        spectrum_files = fd.GetPaths()
        
        if not spectrum_files:
            return []
        
        persist.set_value("doas_spectra_dir", os.path.dirname(spectrum_files[0]))
        
        loader = SpectrumIO()
        spectra = []
        for filename in spectrum_files:
            try:        
                spectra.append(loader.load(filename))
            except Exception,e:
                print e.args
                wx.MessageBox("Unable to load spectrum file \'%s\'. "
                              "Unrecognised file format."%filename, 
                              "AvoPlot", wx.ICON_ERROR)
        return spectra

class FileListPanel(wx.Panel):
    def __init__(self, parent, spec_dir, series):
        super(FileListPanel, self).__init__(parent)
        
        self.spec_loader = SpectrumIO()
        self.spec_dir = spec_dir
        self.series = series
        
        vsizer = wx.BoxSizer(wx.VERTICAL)
        
        hsizer = wx.BoxSizer(wx.HORIZONTAL)
        
        self.spec_dir_box = wx.TextCtrl(self, -1, spec_dir)
        self.browse_button = wx.Button(self, -1, "Browse")
        h_txt = "Select a directory containing spectra."
        self.spec_dir_box.SetToolTipString(h_txt)
        self.browse_button.SetToolTipString(h_txt)
        wx.EVT_BUTTON(self, self.browse_button.GetId(), self.on_browse)
        
        hsizer.Add(self.spec_dir_box, 1, wx.EXPAND|wx.ALIGN_LEFT|wx.ALIGN_CENTRE_VERTICAL|wx.ALL, border=5)
        hsizer.Add(self.browse_button, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTRE_VERTICAL)
        hsizer.AddSpacer(5)
        
        vsizer.Add(hsizer, 0 , wx.EXPAND)
        
        self.spectra = sorted(find_files(spec_dir))
        choices = [os.path.basename(f) for f in self.spectra]
        self.file_list_box = wx.ListBox(self, -1, choices=choices)
        cur_idx = choices.index(os.path.basename(series.filename))
        self.file_list_box.SetSelection(cur_idx)
        evt = wx.CommandEvent(
                wx.wxEVT_COMMAND_LISTBOX_SELECTED, self.file_list_box.GetId())
        evt.SetEventObject(self.file_list_box)
        evt.SetInt(cur_idx)
        evt.SetString(os.path.basename(series.filename))
        wx.PostEvent(self.file_list_box, evt) 
        
        
        vsizer.Add(self.file_list_box, 1, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=5)
        wx.EVT_LISTBOX(self, self.file_list_box.GetId(), self.on_select_spectrum_file)
        
        self.SetSizer(vsizer)
        vsizer.Fit(self)
    
    
    def on_browse(self, evnt):
        
        spec_dir = wx.DirSelector("Select directory containing spectra.", 
                                  defaultPath=self.spec_dir)
        
        if spec_dir == "":
            return
        
        self.spec_dir_box.SetValue(spec_dir)
        
        self.set_spectra_dir(spec_dir)
        
    
    def set_spectra_dir(self, spec_dir):
        self.spectra = sorted(find_files(spec_dir))
        
        self.file_list_box.SetItems([os.path.basename(f) for f in self.spectra]) 
        
        #select the first image in the directory
        self.file_list_box.SetSelection(0)
        self.on_select_spectrum_file(None)
        self.spec_dir = spec_dir
        
    
    def get_current_selection(self):
        try:
            filename_idx = self.file_list_box.GetSelection()
            filename = self.spectra[filename_idx]
            return filename
        except IndexError:
            return None
    
          
    def on_select_spectrum_file(self, evnt):
        
        filename = self.get_current_selection()
        
        try:
            spectrum = self.spec_loader.load(filename)
        except UnableToLoad:
            #its possible that this is just a different type of spectrum file
            #so we create a new loader object and try again
            self.spec_loader = SpectrumIO()
            try:
                spectrum = self.spec_loader.load(filename)
            except UnableToLoad, ex:
                #nope, we really can't load this file type
                wx.MessageBox(ex.args[0], "", wx.ICON_WARNING)
                return 1
        
        self.series.set_name(os.path.basename(filename))
        self.series.set_xy_data(spectrum.wavelengths, spectrum.counts)
        wx.CallAfter(self.series.update)
        
        return 0
        
